/**
   Copyright 2011 Attila Fekete

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

package org.afekete.filemetadatacreator;

import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.afekete.filemetadatacreator.checksum.SHA1Calculator;
import org.afekete.filemetadatacreator.generated.Metadatacollection;
import org.afekete.filemetadatacreator.generated.Metadatacollection.Metadata;
import org.afekete.filemetadatacreator.generated.ObjectFactory;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;

/**
 * This application generates metadata for files.
 * Its output is an xml document with the metadata of files.
 * 
 * Usage:
 * java -jar FileMetaDataCreator.jar -options <output_xml_filename> <path_to_the_files> <filename_with_optional_wildcards>
 * OR 
 * java -jar FileMetaDataCreator.jar -options <output_xml_filename> <pathfilename>
 * 
 * Attention!
 * <filename_with_optional_wildcards> - The \ (backslash) character must be used before wildcard characters in this paramater
 * 
 * @author afekete
 *
 */
public class FileMetaDataCreator {
	
	private static ObjectFactory objFactory = new ObjectFactory();
	private static String versionPath;
	
	public static void main(String[] args) {
		create(args);
		System.exit(0);
	}

	/**
	 * Parses the arguments and executes generation of meta data list of files.
	 * 
	 * @param args command line arguments
	 * @throws JAXBException if something went wrong in result XML generation
	 */
	public static void create(String[] args) {
		
		int paramCounter = 0;
		for (; paramCounter < args.length && !args[paramCounter].endsWith("-options"); paramCounter++);

		if (paramCounter == args.length) System.exit(1); // TODO some error message
		if (args.length < 2 + ++paramCounter) System.exit(1); //TODO some error message about usage
		
		String wildcardedFileName = "*"; // every file will be processed by default
		
		// Process arguments
		File exportFile = new File(args[paramCounter++]);
		File path = new File(args[paramCounter++]);
		versionPath = path.isDirectory() ? path.getAbsolutePath() : path.getPath(); 
		
		if (path.isDirectory()) {
			if (args.length < 1 + paramCounter) System.exit(1); //TODO some error message
			wildcardedFileName = args[paramCounter++].replaceAll("=", "");
		}
		
		List<Metadata> metaDataList = getMetaDataList(new ArrayList<Metadatacollection.Metadata>(), wildcardedFileName, path);
		
		try {
			XMLExporter.export(versionPath, metaDataList, exportFile);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			exportFile.delete();
		} catch (JAXBException e) {
			e.printStackTrace();
			exportFile.delete();
		} catch (IOException e) {
			e.printStackTrace();
			exportFile.delete();
		}
		
	}
	
	/**
	 * Gets list of <code>MetaData</code> objects.
	 * 
	 * @param result list to collect <code>MetaData</code> objects to
	 * @param wildcardedFileName optionally wildcarded file name to create meta data for
	 * @param path file path to process
	 * @return meta data list of files
	 */
	private static List<Metadata> getMetaDataList(List<Metadata> result, String wildcardedFileName, File path) {
		if (path.isDirectory()) {
			FileFilter filter = new WildcardFileFilter(wildcardedFileName);
			File[] files = path.listFiles(filter);
			File[] directories = path.listFiles((FileFilter) DirectoryFileFilter.INSTANCE);
			for (int i = 0; i < directories.length; i++) getMetaDataList(result, wildcardedFileName, directories[i]);
			for (int i = 0; i < files.length; i++) getMetaDataList(result, wildcardedFileName, files[i]);
		} else {
			try {
				result.add(getMetaData(path));
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
		return result;
	}
	
	/**
	 * Gets <code>MetaData</code> object for a single file.
	 * 
	 * @param file <code>File</code> object to process
	 * @return <code>MetaData</code> object for the input file
	 * @throws Exception if something went wrong in checksum calculation
	 */
	private static Metadata getMetaData(File file) throws Exception {
		Metadata result = objFactory.createMetadatacollectionMetadata();
		result.setRelativepath(file.getParent().substring(versionPath.length() + 1));
		result.setName(file.getName());
		result.setSize(new BigDecimal(file.length()));
		result.setChecksum(SHA1Calculator.getSHA1Checksum(file));
		return result;
	}
}
